/*Z Programmable Interval Timer (PIT) 系统时钟API */

/*
 * Copyright 2014, General Dynamics C4 Systems
 *
 * SPDX-License-Identifier: GPL-2.0-only
 */

#include <linker.h>
#include <machine/io.h>
#include <plat/machine/pit.h>

/* PIT (i8253) registers */
#define PIT_MODE 0x43       /*Z 控制端口 */
#define PIT_CH0  0x40       /*Z 通道0数据端口 */

/* Count frequency in Hz */
#define PIT_HZ 1193182      /*Z 晶振器频率 */
/*Z 初始化系统时钟的晶体振荡器，设置IRQ0频率20HZ */
BOOT_CODE void pit_init(void)
{   /*Z 每IRQ0周期晶振次数 */
    uint16_t divisor = (PIT_HZ * PIT_WRAPAROUND_MS) / 1000;
    /*Z 晶振频率/每周期次数=IRQ0频率 */
    out8(PIT_MODE, 0x34);          /* Set mode 2 and wait for divisor bytes */
    out8(PIT_CH0, divisor & 0xff); /* Set low byte of divisor */
    out8(PIT_CH0, divisor >> 8);   /* Set high byte of divisor */
}
/*Z 等待系统时钟内部计数值进入初始值 */
BOOT_CODE void pit_wait_wraparound(void)
{
    uint16_t count;
    uint16_t count_old;

    out8(PIT_MODE, 0x00);           /*Z 锁定晶振器内部记数器值 */
    count = in8(PIT_CH0);           /*Z 读通道0计数器低字节 */
    count |= (in8(PIT_CH0) << 8);   /*Z 读通道0计数器高字节 */
    count_old = count;
    /*Z 计数器是递减的，因此退出条件是计数器回绕为0xFFFF */
    while (count <= count_old) {
        count_old = count;
        out8(PIT_MODE, 0x00);
        count = in8(PIT_CH0);
        count |= (in8(PIT_CH0) << 8);
    }
}
